package com.example.chinesenation.Redis.Impl;

import com.example.chinesenation.Redis.RedisService;
import com.example.chinesenation.Utils.CommonURL;
import javafx.beans.binding.ObjectExpression;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.client.RedisClient;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.DataAccessException;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import static com.example.chinesenation.Utils.CommonURL.InterestProfile;
import static com.example.chinesenation.Utils.RecommendedTools.InterestSize;

/**
 * @author sakuraFallingDown
 * @version 1.0
 * @date 2021/1/11 16:31
 */
@Configuration
public class RedisServiceImpl implements RedisService {//redis服务类
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    //@Autowired
    //private RedissonClient  redissonClient;

    @Override
    public void put(String key, Object o) {//永久存储

        redisTemplate.opsForValue().set(key,o);
    }



    @Override
    public Object get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    @Override
    public void increasePageView(String key) {
        redisTemplate.opsForValue().increment(key);
    }

    @Override
    public void initPageView(String key, int pageview) {//初始时建立阅读量
        redisTemplate.opsForValue().increment(key,pageview);
    }

    @Override
    public void put(String key, Object o, long expireTime) {//按照小时存储
        redisTemplate.opsForValue().set(key,o,expireTime, TimeUnit.HOURS);
    }
    @Override
    public void putMinute(String key, Object o, long expireTime) {
        redisTemplate.opsForValue().set(key,o,expireTime, TimeUnit.MINUTES);
    }

    @Override
    public void putSecond(String key, Object o, long expireTime) {
        redisTemplate.opsForValue().set(key,o,expireTime, TimeUnit.SECONDS);
    }
    @Override
    public void delete(String key) {
        redisTemplate.delete(key);
    }

    @Override
    public boolean hasKey(String key) {//判断是否含有该key，并且判断是否为空，充当布隆过滤器功能
        if(key==null) return false;
        else {
            return redisTemplate.hasKey(key) && redisTemplate.opsForValue().get(key) != null;
        }
    }

    @Override
    public boolean hasComment(String key) {
        if(key==null) return false;
        else {
            return redisTemplate.hasKey(key);
        }
    }

    @Override
    public void addPageView(String key,String ip) {
        redisTemplate.opsForHyperLogLog().add(key,ip);
    }

    @Override
    public int getPageView(String key) {
        String str=""+redisTemplate.opsForHyperLogLog().size(key);

        return Integer.parseInt(str);
    }

    @Override
    public void deletePageView(String key) {
        redisTemplate.delete(key);
    }

    @Override
    public Set<String> getAllArticlePageViewKeys() {
        return redisTemplate.keys(CommonURL.RedisArticlePageView+"*");
    }

    @Override
    public Set<String> getAllPolicyPageViewKeys() {
        return redisTemplate.keys(CommonURL.RedisPolicyPageView+"*");
    }

    //用于推荐的函数
    @Override
    public void initUserInterest(String uid) {//初始化为0
        for(int index=0;index<InterestSize;index++){//一共11个用户兴趣矩阵
            redisTemplate.opsForList().leftPush(InterestProfile+uid,1.0);
            for(int i=0;i<10;i++){
                redisTemplate.opsForList().leftPush(InterestProfile+uid+":"+index,0.0);
            }
        }
    }

    @Override
    public List<Object> getUserInterest(String uid, int type) {
        return redisTemplate.opsForList().range(InterestProfile+uid + ":" + type, 0, -1);
    }

    @Override
    public List<Object> getUserMainInterest(String uid) {
        return redisTemplate.opsForList().range(InterestProfile+uid , 0, -1);
    }

    @Override
    public void changeUserInterest(String uid, int type, List<Double> interest) {
        List<Object> range =getUserInterest(uid,type);
        if(range!=null&&range.size()==interest.size()) {
            for (int index = 0; index < interest.size(); index++) {
                redisTemplate.opsForList().set(InterestProfile+uid+":"+type,
                        index,
                        ((Double) range.get(index)) + interest.get(index));
            }
        }
    }

    @Override
    public void changeUserMainInterest(String uid, int type, Double score) {
        List<Object> range =getUserMainInterest(uid);
        redisTemplate.opsForList().set(InterestProfile+uid,type,(Double)range.get(type)+score);//修改用户主兴趣矩阵
    }

    @Override
    public <T> List<T> pipeline(List<String> keys, T t) {
        List<Object> objects = redisTemplate.executePipelined(new RedisCallback<T>() {
            @Override
            public T doInRedis(RedisConnection redisConnection) throws DataAccessException {
                redisConnection.openPipeline();
                for(String key:keys){
                    redisConnection.get(key.getBytes());
                }
                return null;
            }
        });
        List<T> temp=new ArrayList<>(objects.size());
        for(Object o:objects){
            temp.add((T)o);
        }
        return temp;
    }

    @Override
    public void pipelineZSet(String key,List<String> keys, List<Long> values) {
        redisTemplate.executePipelined(new RedisCallback<Object>() {
            @Override
            public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
                for(int i=0;i<keys.size();i++){
                    redisConnection.zIncrBy(key.getBytes(),values.get(i),keys.get(i).getBytes());
                }
                return null;
            }
        });
    }
}
